from classes.Participante import Participante
from random import randint, random

class Leilao:
    def __init__(self, parametros):
        self.numeroDeParticipantes = parametros.numeroDeParticipantes
        self.aumentoMinimo = parametros.aumentoMinimo
        self.valorInicial = parametros.valorInicial

        self.valorAtual = 0
        self.vencedorAtual = -1
        self.autorDoLance = list()
        self.historicoDosLances = list()
        self.participantes = list()

        self.participantes = self.numeroDeParticipantes * [None]
        if parametros.perfeitamenteRacionais == True:
            for i in range(self.numeroDeParticipantes):
                self.participantes[i] = Participante(parametros)
        else:
            for i in range(parametros.quantidadeDeParticipantesCautelosos):
                self.participantes[i] = Participante(parametros, perfil="cauteloso")

            for i in range(parametros.quantidadeDeParticipantesCautelosos, parametros.quantidadeDeParticipantesCautelosos + parametros.quantidadeDeParticipantesModerados):
                self.participantes[i] = Participante(parametros, perfil="moderado")

            for i in range(parametros.quantidadeDeParticipantesCautelosos + parametros.quantidadeDeParticipantesModerados, parametros.quantidadeDeParticipantesCautelosos + parametros.quantidadeDeParticipantesModerados + parametros.quantidadeDeParticipantesAgressivos):
                self.participantes[i] = Participante(parametros, perfil="agressivo")

        self.participando = self.numeroDeParticipantes * [True]
        self.somaDosTemposDeResposta = self.somaTempos()

        if parametros.perfeitamenteRacionais == False:
            self.selecionaAliancas()
            self.selecionaRivalidades()

    def iniciaLeilao(self):
        while self.participando.count(True) > 1:
            i = self.escolheProximoParticipante()

            if self.vencedorAtual == i:
                continue

            oferta = self.participantes[i].fazOferta(self.valorInicial, self.valorAtual, self.aumentoMinimo, self.vencedorAtual)

            if oferta == None:
                if self.participando.count(True) == 2:
                    break

                continue

            if oferta == False:
                self.participanteDesiste(i)
                continue

            self.atualizaValor(oferta, i)

            if self.participantes[i].participanteAliado != None and random() <= 0.05:
                self.quebraAlianca(i)

        return self.historicoDosLances, self.autorDoLance

    def escolheProximoParticipante(self):
        soma = self.somaDosTemposDeResposta
        if self.vencedorAtual != -1:
            soma -= self.participantes[self.vencedorAtual].tempoDeResposta

        num = randint(1, soma)
        acumulador = int(0)

        for i in range(self.numeroDeParticipantes):
            if self.participando[i] == False or i == self.vencedorAtual:
                continue

            acumuladorTemporario = acumulador + self.participantes[i].tempoDeResposta

            if acumuladorTemporario >= num and acumulador < num:
                break

            acumulador = acumuladorTemporario

        return i

    def somaTempos(self):
        soma = int(0)

        for i in range(self.numeroDeParticipantes):
            soma += self.participantes[i].tempoDeResposta

        return soma

    def participanteDesiste(self, indice):
        self.participando[indice] = False
        self.somaDosTemposDeResposta -= self.participantes[indice].tempoDeResposta

    def atualizaValor(self, valor, participante):
        self.valorAtual = valor
        self.vencedorAtual = participante

        self.historicoDosLances.append(valor)
        self.autorDoLance.append(participante)

    def selecionaAliancas(self):
        sorteado = random()
        numeroDeAliancas = 0
        participantesSemAliado = float(self.numeroDeParticipantes)

        while sorteado < (participantesSemAliado / (participantesSemAliado + 40)):
            participante1 = randint(0, self.numeroDeParticipantes - 1)
            participante2 = randint(0, self.numeroDeParticipantes - 1)

            if participante1 == participante2 or self.participantes[participante1].participanteAliado != None or self.participantes[participante2].participanteAliado != None:
                continue

            self.participantes[participante1].participanteAliado = participante2
            self.participantes[participante2].participanteAliado = participante1

            participantesSemAliado -= 2
            numeroDeAliancas += 1

            if numeroDeAliancas >= self.numeroDeParticipantes / 4:
                break

            sorteado = random()

    def selecionaRivalidades(self):
        sorteado = random()
        numeroDeRivalidades = 0
        participantesSemRival = float(self.numeroDeParticipantes)

        while sorteado < (participantesSemRival / (participantesSemRival + 40)):
            participante1 = randint(0, self.numeroDeParticipantes - 1)
            participante2 = randint(0, self.numeroDeParticipantes - 1)

            if participante1 == participante2 or self.participantes[participante1].participanteRival != None or self.participantes[participante2].participanteRival != None:
                continue

            if self.participantes[participante1].participanteAliado == participante2 or self.participantes[participante2].participanteAliado == participante1:
                continue

            self.participantes[participante1].participanteRival = participante2
            self.participantes[participante2].participanteRival = participante1

            participantesSemRival -= 2
            numeroDeRivalidades += 1

            if numeroDeRivalidades >= self.numeroDeParticipantes / 4:
                break

            sorteado = random()

    def quebraAlianca(self, participante):
        aliado = self.participantes[participante].participanteAliado

        self.participantes[participante].participanteAliado = None
        self.participantes[aliado].participanteAliado = None
